﻿using System.Collections.Generic;
using System.Linq;
using LINQtoFxCop.Core;
using Microsoft.FxCop.Sdk;

namespace LINQtoFxCop.DomainSpecific.GreyZone
{
  internal sealed class TestForEmptyStringsUsingStringLength : DomainSpecificIntrospectionRule
  {
    // Fields
    private bool _issueFound;
    private static Field _emptyString;

    public TestForEmptyStringsUsingStringLength()
      : base("TestForEmptyStringsUsingStringLength")
    { }
    public override void AfterAnalysis()
    {
      base.AfterAnalysis();
      _emptyString = null;
    }

    public override void BeforeAnalysis()
    {
      if (_emptyString == null)
        _emptyString = FrameworkTypes.String.GetField(Identifier.For("Empty"));
      base.BeforeAnalysis();
    }

    protected override IEnumerable<QueryResult> Query()
    {
      return
        from method in Methods
        where CheckMethod(method)
        select Result(method);
    }
    private bool CheckMethod(Method method)
    {
      _issueFound = false;
      VisitMethod(method);
      return _issueFound;
    }

    public override void VisitMethodCall(MethodCall call)
    {
      string str;
      MemberBinding callee = call.Callee as MemberBinding;
      if (callee == null)
        return;
      Member boundMember = callee.BoundMember;
      if (((boundMember.DeclaringType == FrameworkTypes.String) && ((str = boundMember.Name.Name) != null)) && (((str == "op_Equality") || (str == "op_Inequality")) || (str == "Equals")))
      {
        MetadataCollection<Expression>.Enumerator enumerator = call.Operands.GetEnumerator();
        while (enumerator.MoveNext())
        {
          Expression current = enumerator.Current;
          if (FindIssue(current))
          {
            break;
          }
        }
        FindIssue(callee.TargetObject);
      }
      base.VisitMethodCall(call);
    }

    private bool FindIssue(Expression expr)
    {
      if (expr != null)
      {
        Literal literal = expr as Literal;
        if (literal != null)
        {
          string str = literal.Value as string;
          if ((str != null) && (str.Length == 0))
          {
            _issueFound = true;
            return true;
          }
        }
        MemberBinding binding = expr as MemberBinding;
        if ((binding != null) && (binding.BoundMember.FullName == _emptyString.FullName))
        {
          _issueFound = true;
          return true;
        }
      }
      return false;
    }
    public override TargetVisibilities TargetVisibility
    {
      get
      {
        return (TargetVisibilities.AnonymousMethods | TargetVisibilities.Overridable | TargetVisibilities.NotExternallyVisible | TargetVisibilities.ExternallyVisible);
      }
    }

  }
}
